package com.link_with_health.controller;

import com.alibaba.fastjson.JSONObject;
import com.link_with_health.common.Page;
import com.link_with_health.common.Result;
import com.link_with_health.common.TokenMap;
import com.link_with_health.common.VerifyUserUtil;
import com.link_with_health.exception.AuthenticationFailedException;
import com.link_with_health.exception.BaseException;
import com.link_with_health.exception.NullQueryResultException;
import com.link_with_health.model.AdminLogEntity;
import com.link_with_health.model.AdminUserEntity;
import com.link_with_health.model.BatchModel;
import com.link_with_health.model.DoctorEntity;
import com.link_with_health.model.UserEntity;
import com.link_with_health.service.AdminLogService;
import com.link_with_health.service.BatchOperationService;
import com.link_with_health.service.UserService;
import com.link_with_health.utils.JsonUtil;
import org.apache.catalina.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.jws.soap.SOAPBinding;
import javax.servlet.http.HttpServletRequest;

import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.HashMap;

@Controller
@RequestMapping("/api/user")
public class UserController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String AUTH_TOKEN = "Authorization";
    private TokenMap tokenMap = TokenMap.getInstance();

    @Resource(name = "userService")
    UserService userService;

    @Resource(name = "adminLogService")
    AdminLogService adminLogService;

    @Resource(name = "batchOperationService")
    BatchOperationService batchOperationService;

    private final int[] USER_INVISIBLE = {4};
    private final int[] USER_CANNOT_CHANGE = {3,5,6};

    /**
     *  获取用户信息
      * @param json 数据
     * @param request 请求
     * @return 结过
     */
    @RequestMapping("/findUserInfo")
    @ResponseBody
    public Result findUserInfo(@RequestBody JSONObject json
            , HttpServletRequest request) {
        String msg = "获取失败 ";
        String token =  request.getHeader(AUTH_TOKEN);
        if(token == null ||!tokenMap.containsKey(token)){
            logger.error("[not token ]");
            return Result.fail(msg);
        }
        String method = (String) json.get("method");
        try {
            HashMap<String,Object> params = (HashMap<String, Object>) json.get("params");

            return method(method,params);

        } catch (Exception e) {
            logger.error("[get userInfo failed]",e);
            msg = "获取数据失败";
        }
        return Result.fail(msg);
    }

    /**
     *  修改用户信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/modifyUserInfo")
    @ResponseBody
    public Result modifyUserInfo(@RequestBody Map<String,Object> json
            , HttpServletRequest request) {
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "请求失败 验签失败";
        if(token == null || tokenMap.get(token) == null) {
            logger.error("[access message by token failed "
                    + "from " + request.getRemoteAddr() + "]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());


        try {


            UserEntity entity = JsonUtil.map2obj(json,UserEntity.class);

            UserEntity olderEntity = userService.getUserByUserId(entity.getUserId());

            try {
                if (olderEntity.getTelephone().equals(entity.getTelephone())) {
                    logger.info("[phone not change]");
                } else if (userService.getUserByPhone(entity.getTelephone()) != null) {
                    logger.warn("[phone is used]");
                    return Result.fail("手机已被使用");
                }
            }catch(Exception e){
                if (e instanceof NullQueryResultException)
                    logger.info("[phone is not used]");
                else
                    logger.warn("[error =>]",e);
            }
            try{

                if(olderEntity.getEmail().equals(entity.getEmail())){
                    logger.info("[email not used]");
                }
                else if(userService.getUserByEmail(entity.getEmail()) != null){
                    logger.warn("[email is used]");
                    return Result.fail("邮箱已被使用");
                }
            }catch(Exception e){
                if (e instanceof NullQueryResultException)
                    logger.info("[phone is not used]");
                else
                    logger.warn("[error =>]",e);
            }


            UserEntity oldEntity = userService
                    .getUserByUserId(entity.getUserId());

            userService.changeUser(entity);
            entity = userService
                    .getUserByUserId(entity.getUserId());

            //备份
            String object = JsonUtil.obj2json(oldEntity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "修改", "doctor", object);

            adminLogService.addAdminLog(log);


            return Result.success(entity);

        } catch (Exception e) {
            logger.error("[modify user failed]",e);
            msg = "修改数据失败";
        }
        return Result.fail(msg);
    }


    /**
     *
     * @param json
     * @param request
     * @return
     */
    @RequestMapping("/addUserInfo")
    @ResponseBody
    public Result addUserInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }
        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        try{
            UserEntity entity = JsonUtil
                    .json2obj(json.toJSONString(), UserEntity.class);

            try{
                if(userService.getUserByPhone(entity.getTelephone()) != null){
                    logger.warn("[phone is used]");
                    return Result.fail("手机已被使用");
                }
            }catch(Exception e){
                if(e instanceof NullQueryResultException)
                    logger.info("[phone is not used]");
                else
                    logger.warn("[error =>]",e);
            }
            try {
                if (userService.getUserByEmail(entity.getEmail()) != null) {
                    logger.warn("[email is used]");
                    return Result.fail("邮箱已被使用");
                }
            }catch(Exception e){
                if(e instanceof NullQueryResultException)
                    logger.info("[phone is not used]");
                else
                    logger.warn("[error=>]",e);
            }


            userService.addUser(entity);
            entity = userService.getUserByUserId(entity.getUserId());

            //备份
            String object = JsonUtil.obj2json(entity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "增加", "user", object);

            adminLogService.addAdminLog(log);

            return Result.success("成功修改",entity);

        } catch(Exception e){
            logger.error("[add user info failed]",e);
            msg = "添加失败";
        }

        return Result.fail(msg);
    }

    @RequestMapping("/deleteUserInfo")
    @ResponseBody
    public Result deleteUserInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[delete sysInfo info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());
        int errorNumber = 0;
        try{
            Long[] ids = json.getObject("ids",Long[].class);
            //备份
            StringBuilder oldEntity = new StringBuilder();

            for(Long idBk: ids){
                UserEntity entity = userService.getUserByUserId(idBk);
                oldEntity.append("\n").append(JsonUtil.obj2json(entity));
            }
            List<BatchModel> models = new ArrayList<>(ids.length);
            int index = 0;
            String sql = "user_Name = 'null', user_PW = '123'" +
                    ", telephone = '123' , is_Doctor=false," +
                    " gender=0, email=@com, user_status= 4," +
                    " ip_lock= '0.0.0.0' ";

            for(; index < ids.length; index++){
                BatchModel model = new BatchModel("user"
                        , "","",
                        "user_id",ids[index].toString(),sql);
                models.add(model);
            }

            batchOperationService.batchUpdateLikeDelete(models);

            //记录操作
            AdminLogEntity log = new AdminLogEntity(0L, adminId,
                    "删除", "user", oldEntity.toString());
            adminLogService.addAdminLog(log);

            return Result.success("成功操作");

        }catch(Exception e){
            logger.error("delete doctor failed",e);
            msg = "删除失败";
        }

        return Result.fail(msg);
    }

    /**
     * 通过id获取用户信息
     * @param json json - userId
     * @param request 请求
     * @return  返回的数据
     */
    @RequestMapping("/selectUserInfoById")
    @ResponseBody
    public Result selectUserById(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "请求失败 验签失败";

        try{
            Long userId = json.getLong("userId");
            UserEntity entity = userService
                    .getUserByUserId(userId);
            return Result.success(entity);

        }catch(Exception e){
            logger.error("[get user info failed]",e);
            msg = "获取数据失败";
        }

        return Result.fail(msg);
    }


    /**
     * 获取当前用户信息
     * @param request 请求
     * @return 用户数据
     */
    @GetMapping("/accessUser")
    @ResponseBody
    public Result accessUser(HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签校验失败 无权限";
        if(token == null || tokenMap.get(token) == null) {
            logger.error("[access message by token failed "
                   +"from " + request.getRemoteAddr() +"]");
            logger.error("[verify user token failed]");

            return Result.fail(msg);
        }
        try{
            System.out.println("[user token => "+token);

            UserEntity user = (UserEntity) tokenMap.get(token);
            user = userService.getUserByUserId(user.getUserId());
            //屏蔽密码
            user.setPassword("*******");
            return Result.success(user);

        } catch(Exception e) {
            logger.error("[access userInfo failed]");
            msg="获取用户数据失败";
        }

        return Result.fail(msg);
    }

    /**
     * 获取状态列表
     * @param request 请求
     * @return 数据
     */
    @RequestMapping("/getUserStatus")
    @ResponseBody
    public Result getUserStatus(HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签校验失败 无权限";
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("not token");
            return Result.fail(msg);
        }

        try{

            return Result.success(userService.getAllUserStatus());

        }catch(Exception e){
            logger.error("[get status failed]",e);
            msg = "获取用户状态信息失败";
        }

        return Result.fail(msg);
    }

    /**
     * 编辑用户信息
     * @param json
     * @param request
     * @return
     */
    @PostMapping("/editUserInfo")
    @ResponseBody
    public Result editUserInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String msg = "验签校验失败 无权限";
        String token = request.getHeader(AUTH_TOKEN);
        if(token == null || tokenMap.get(token) == null) {
            logger.error("[verify user token failed" +
                    ", edit user failed]");

            return Result.fail(msg);
        }
        try{
            Long idInToken = ((UserEntity)tokenMap.get(token)).getUserId();
            Long userId = json.getLong("userId");
            if(userId.equals(idInToken)) {
                logger.error("[userId don't match=>"+userId+"]");
                throw new AuthenticationFailedException
                        ("USERID DON'T MATCH");
            }

            UserEntity entity = userService
                    .getUserByUserId(userId);

            entity.setUsername(json.getString("username"));
            entity.setEmail(json.getString("email"));
            entity.setTelephone(json.getString("telephone"));
            entity.setGender(json.getShort("gender"));

            userService.changeUser(entity);

        }catch(Exception e){
            logger.error("[edit user failed]",e);
            msg = "修改信息失败";
        }

        return Result.fail(msg);
    }

    public Result updateUserPassword(@RequestBody JSONObject json
            , HttpServletRequest request){
        String msg = "验签校验失败 无权限";
        String token = request.getHeader(AUTH_TOKEN);
        if(token == null || tokenMap.get(token) == null) {
            logger.error("[verify user token failed" +
                    ", edit user failed]");
            return Result.fail(msg);
        }

        try {
            String password = json.getString("password");
            String currentPassword = json.getString("currentPassword");

            Long userId = json.getLong("userId");

            Long idInToken = ((UserEntity)tokenMap
                    .get(token)).getUserId();

            if(userId.equals(idInToken)) {
                logger.error("[userId don't match=>"+userId+"]");
                throw new AuthenticationFailedException
                        ("USERID DON'T MATCH");
            }

            UserEntity entity = userService.getUserByUserId(userId);
            if(!entity.getPassword().equals(password)){
                logger.error("[password don't match]");
                throw new AuthenticationFailedException
                        ("PASSWORD DON'T MATCH");
            }

            entity.setPassword(currentPassword);
            userService.changeUser(entity);

        } catch(Exception e){
            logger.error("[edit password failed]",e);
            msg = "修改失败";
        }

        return Result.fail(msg);
    }

    private Result method(String method, Map<String,Object> params)
            throws Exception{
        List<UserEntity> list = new ArrayList<>();

        switch(method){
            case "all": case "all-page":{
                list = userService.getAllUsers();

            }
                break;
            case "name": case "name-page":{
                String name = String.valueOf(params.get("name"));
                list = userService.getAllUsers()
                        .stream()
                        .filter(item ->( item.getUsername() != null
                                && item.getUsername().contains(name)))
                        .collect(Collectors.toList());
            }
                break;
            case "id": case "id-page":{
                Long id = Long.valueOf(
                        String.valueOf(params.get("id")));
                list.add(userService.getUserByUserId(id));

            }
                break;
            default:
                logger.error("unknown method=>" + method);
                return Result.fail("未知查找方法");
        }
        if(list == null || list.isEmpty())
            throw new NullQueryResultException("[not result fo doctor]");
        list = list.stream().distinct()
                .filter(this::isVisible)
                .collect(Collectors.toList());

        //封装 带页数数据
        if(method.contains("page")){
            Integer current = Integer.valueOf(String.valueOf(params.get("current"))) ;
            Integer size = Integer.valueOf(String.valueOf(params.get("size")));
            Page<UserEntity> page = new Page<>(list, size, current);
            return Result.success(page.getPageDate());
        }

        return Result.success(list);
    }


    private boolean isVisible(UserEntity entity){
        if(entity != null && entity.getUserStatus() != null)
            return isVisible(entity.getUserStatus());
        else
            return false;
    }

    private boolean isVisible(int status){
        for (int num : USER_INVISIBLE){
            if(num == status)
                return false;
        }
        return true;
    }
}
